/*============================================================================
  File:      DmhMemory.h
 
  Summary:   Declaration of helper classes and functions for allocating memory

  Date:		 June 30, 2004
------------------------------------------------------------------------------
  This file is part of the Microsoft SQL Server Code Samples.
 
  Copyright (C) 2003 Microsoft Corporation.  All rights reserved.
 
This source code is intended only as a supplement to Microsoft
Development Tools and/or on-line documentation.  See these other
materials for detailed information regarding Microsoft code samples.
 
THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
============================================================================*/

#pragma once
#include <atlcom.h>
#include "..\..\dmalgo.h" 

// Useful macro

#define RETURN_ON_FAIL(hr)	\
{							\
	if (!SUCCEEDED(hr))		\
	{						\
		return hr;			\
	}						\
}

// DMHALLOC is a wrapper structure around a IDMMemoryAllocator smart
// pointer. This structure should be used for all (placement) new calls,
// and the assocated Delete().

struct DMHALLOC
{
	DMHALLOC()
	{
	}

	HRESULT	SetAllocator(IDMServices* pidmservices);
	HRESULT	SetAllocator(IDMMemoryAllocator* pidmmemoryallocator);
	HRESULT	SetAllocator(DMHALLOC& dmhalloc);

	CComPtr<IDMMemoryAllocator> _spidmmemoryallocator;
};

// Any class that does dynamic-memory allocation can derive from DMHALLOC... this
// is particularly convenient when your class has STL members. For example:
// 
// class MYCLASS : public DMHALLOC
// {
//	 public:
//		
//		dm_vector<int> _vint;	// Requires a DMHALLOC on construction
//	
//		MYCLASS() : _vint(*this) // DMHALLOC always available
//		{
//		}
// };


// You need to use the following placement new and Delete() whenever
// allocating and deallocating memory, respectively.

void* operator new(size_t sizet, DMHALLOC& dmhalloc);

template<class T>
void Delete(T* pt, DMHALLOC& dmhalloc)
{
	// Make an explicit call to the class destructor before freeing
	// the memory.

	pt->~T();

	dmhalloc._spidmmemoryallocator->Free((byte*) pt);
}

// The following placement delete is defined so that if your
// constructor throws an exception, the memory for your class
// gets cleaned up. You should never call this operator explicitly.

void operator delete(void* pv, DMHALLOC& dmhalloc);

// Version of CComObject that uses a DMHALLOC to allocate and deallocate 
// memory. The base class Base must derive from DMHALLOC. CreateInstance()
// will set the new class' memory allocator to be the same as the one used
// to create the class.

//Base is the user's class that derives from CComObjectRoot and whatever
//interfaces the user wants to support on the object

template <class Base>
class CComObjectDM : public CComObject<Base>
{
public:

	STDMETHOD_(ULONG, Release)()
	{
		ULONG l = InternalRelease();
		if (l == 0)
		{
			Delete(this, *this);
		}
		return l;
	}

	static HRESULT WINAPI CreateInstance(DMHALLOC& dmhalloc, 
										 CComObjectDM<Base>** pp) throw();
};



template <class Base>
HRESULT WINAPI CComObjectDM<Base>::CreateInstance(DMHALLOC& dmhalloc, 
												  CComObjectDM<Base>** pp) throw()
{
	ATLASSERT(pp != NULL);
	if (pp == NULL)
		return E_POINTER;
	*pp = NULL;

	HRESULT hRes = E_OUTOFMEMORY;
	CComObjectDM<Base>* p = NULL;

	ATLTRY(p = new(dmhalloc) CComObjectDM<Base>());

	if (p != NULL)
	{
		p->SetAllocator(dmhalloc);
		p->SetVoid(NULL);
		p->InternalFinalConstructAddRef();
		hRes = p->FinalConstruct();
		if (SUCCEEDED(hRes))
			hRes = p->_AtlFinalConstruct();
		p->InternalFinalConstructRelease();
		if (hRes != S_OK)
		{
			delete p;
			p = NULL;
		}
	}
	*pp = p;
	return hRes;
}

	
	